-
Notifications
You must be signed in to change notification settings - Fork 12.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hierarchical refactorings #41975
Hierarchical refactorings #41975
Conversation
Thanks for the PR! It looks like you've changed the TSServer protocol in some way. Please ensure that any changes here don't break consumers of the current TSServer API. For some extra review, we'll ping @sheetalkamat, @amcasey, @mjbvz, @minestarks for you. Feel free to loop in other consumers/maintainers if necessary |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just some minor nits. Looks good otherwise.
*/ | ||
export function refactorKindBeginsWith(known: string, requested: string | undefined): boolean { | ||
if(!requested) return true; | ||
return known.substr(0, requested.length) === requested; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return known.substr(0, requested.length) === requested; | |
return known.startsWith(requested); | |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
* Checks if some refactor info has refactor error info. | ||
*/ | ||
export function isRefactorErrorInfo(info: unknown): info is RefactorErrorInfo { | ||
return (info as RefactorErrorInfo).error !== undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
return (info as RefactorErrorInfo).error !== undefined; | |
return 'error' in info; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is what I wanted to do, but for some reason we forbid it though a lint rule:
Error: C:\Repos\TypeScript-GH\src\services\refactors\helpers.ts:14:16 no-in-operator Don't use the 'in' keyword - use 'hasProperty' to check for key presence instead
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this. The names look good to me and the behavior you describe sounds correct to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The protocol changes look good and I did a few other spot checks.
* Checks if string "known" begins with string "requested". | ||
* Used to match requested refactorKinds with a known refactorKind. | ||
*/ | ||
export function refactorKindBeginsWith(known: string, requested: string | undefined): boolean { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just to confirm, this doesn't require matching full hierarchy levels, right? So I can get all the extractions with "refactor.e"?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. I experimented with something fancier but it didn't seem to add anything except code complexity.
it would be sorta nice if we could provide string completions for the refactor kinds, but I couldn't think of anything besides just listing them all out in a big union in the refactorKind
type.
const extractToTypeAliasAction = { | ||
name: "Extract to type alias", | ||
description: getLocaleSpecificMessage(Diagnostics.Extract_to_type_alias), | ||
refactorKind: "refactor.extract.type", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it redundant to have every refactorKind start with "refactor."?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an LSP naming convention that VSCode also tries to follow for it's keybinding names:
https://microsoft.github.io/language-server-protocol/specifications/specification-3-14/#textDocument_codeAction
It felt premature to chop off the "refactor"
bit without knowing how our codeAction
routing will ultimately look.
* Add support for TS's Hierarchical refactorings API microsoft/TypeScript#41975 * Add simple browser extension This change adds a new 'simple browser' extension. This extension uses a webview to render webpages directly in VS Code. We plan on using it for optionally previewing local servers in both desktop and codespaces The browser itself has a number of limitations due to the security around iframes: - It traps keyboard focus - We can't detect if a page fails to load - We can't track the current url of the iframe * Add experimental alert when the iframe is focused * Disable events on focus warning * Hooking up simple browser to opener
Fixes #35096
Adds
refactorKind
strings to theGetApplicableRefactorsRequest
to allow editors to request a specific refactor action or set of refactors/actions. I list them here along with the old names:"Add or remove braces in an arrow function"
"Convert arrow function or function expression"
"Convert export"
"Convert import"
"Convert overload list to single signature"
"refactor.rewrite.function.overloadList"
"Convert parameters to destructured object"
"refactor.rewrite.parameters.toDestructured"
"Convert to template string"
"refactor.rewrite.string"
"Convert to optional chain expression"
"refactor.rewrite.expression.optionalChain"
"Extract Symbol"
"Extract type"
"Generate 'get' and 'set' accessors"
"refactor.rewrite.property.generateAccessors"
"Infer function return type"
"refactor.rewrite.function.returnType"
"Move to a new file"
"refactor.move.newFile"
cc @mjbvz for input on the names. I intend to follow the VSCode/LSP style where it applies - others I made up.
getAvailableRefactors
will now compare the requestedrefactorKind
to the set of actions available to each action before checking for applicable refactors. This allows us to skip out on unnecessary work if a specific action was requested. IfrefactorKinds
is undefined we check each refactor as usual.A 0-index substring of a
refactoKind
should return every action that would complete the requestedrefactorKind
. That is, ifrefactor.extract
is requested, we should return all ofThe most specific
refactorKind
applicable should always be returned.The current error behavior is to return all refactor actions available to a given refactor along with their error messages, and return no error messages if at least one refactor action is applicable. I did not intend to modify that here but it might be good to change it to return all actions that matched a request, applicable and erroring, if editors can support it.
Since I was modifying the returned actions and had to add some error messages I did some refactoring around those to make things more consistent/readable. The crux of the change is in
refactorProvider.ts
andprotocol.ts
.